#include <QtDebug>

#include <gloox/client.h>
#include <gloox/connectiontcpclient.h>
#include <gloox/rostermanager.h>

#include "connection.h"
#include "loghandler.h"
#include "sessionthread.h"
#include "glooxhelpers.h"
#include "../account.h"
#include "../accountstore.h"
#include "../ui/ui_rosterwidget.h"

static const int DEFAULT_PORT = 5222;

struct Kajim::XMPP::Connection::Private
{
    int accountHandler;
    gloox::Client * client;
    int socket;
    SessionThread * sessionThread;
    bool connectionConnected;
    QMap<QString, gloox::MessageSession*> messageSessions;
};

Kajim::XMPP::Connection::Connection(int accountHandler)
    : QObject()
{
    d = new Private;
    d->accountHandler = accountHandler;
    d->connectionConnected = false;

    Kajim::AccountStore * store = Kajim::AccountStore::instance();
    Kajim::Account * account = store->account(d->accountHandler);

    QString jid_string = account->param("jid") + "/" + account->param("resource");
    QString password = account->param("stored_password");

    gloox::JID j(jid_string.toStdString());
    d->client = new gloox::Client(j, password.toStdString());
    d->client->setTls(gloox::TLSDisabled); // debug
    d->client->setSasl(false); // debug
    d->client->registerConnectionListener(this);
    d->client->registerPresenceHandler(this);
    d->client->logInstance().registerLogHandler(gloox::LogLevelDebug, gloox::LogAreaAll,
            Kajim::XMPP::getLogHandler());
    d->client->registerMessageSessionHandler(this, 0);

    d->sessionThread = new Kajim::XMPP::SessionThread(d->client, this);

    qDebug() << "creating Connection object";
}

Kajim::XMPP::Connection::~Connection()
{
    delete d->client;
    delete d;
}

gloox::Presence Kajim::XMPP::Connection::presence()
{
    return d->client->presence();
}

void Kajim::XMPP::Connection::onConnect()
{
    d->connectionConnected = true;
    emit connected(d->accountHandler);
}

void Kajim::XMPP::Connection::onDisconnect(gloox::ConnectionError e)
{
    qDebug() << "connection disconnected for account" << d->accountHandler << ", connection error: " << e;
    // gloox::ConnUserDisconnected==17, gloox::ConnStreamClosed==3
    // workaround for situation when onDisconnect() is called twice
    if (d->connectionConnected) {
        d->connectionConnected = false;
        emit disconnected(d->accountHandler);
    }

    emit connectionError(e);
}

bool Kajim::XMPP::Connection::onTLSConnect(const gloox::CertInfo& info)
{

}

void Kajim::XMPP::Connection::handlePresence(gloox::Stanza * stanza)
{

}

// from gloox::MessageSessionHandler
void Kajim::XMPP::Connection::handleMessageSession(gloox::MessageSession *session)
{
    qDebug() << "message session request" << (void*)session;
    session->registerMessageHandler(this);
    const gloox::JID & target = session->target();
    qDebug() << "target JID" << QString::fromStdString(target.full());
}

void Kajim::XMPP::Connection::handleMessage(gloox::Stanza *stanza, gloox::MessageSession *session)
{
    QString body = Kajim::XMPP::string(stanza->body());
    QString subject = Kajim::XMPP::string(stanza->subject());
    QString peerJid = Kajim::XMPP::string(stanza->from().full());

    emit messageReceived(d->accountHandler, peerJid, body, subject);

    qDebug() << "got message:" << body;
}

bool Kajim::XMPP::Connection::isConnected()
{
    return d->connectionConnected;
}

QString Kajim::XMPP::Connection::contactName(const QString & jid)
{
    // TODO: add actual code
    return jid;
}

gloox::RosterManager * Kajim::XMPP::Connection::rosterManager()
{
    if (presence() == gloox::PresenceUnavailable) {
        return 0;
    }

    return d->client->rosterManager();
}

gloox::MessageSession * Kajim::XMPP::Connection::messageSession(const QString & jid)
{
    gloox::MessageSession * ms;
    if (d->messageSessions.contains(jid)) {
        return d->messageSessions[jid];
    }

    gloox::JID j(jid.toStdString());
    ms = new gloox::MessageSession(d->client, j);
    //const gloox::JID & target = session->target();
    //qDebug() << "target JID" << QString::fromStdString(target.full());
    d->client->registerMessageSession(ms);
    return ms;
}

void Kajim::XMPP::Connection::login(gloox::Presence presence)
{
    Kajim::AccountStore * store = Kajim::AccountStore::instance();
    Kajim::Account * account = store->account(d->accountHandler);

    if (account == 0) {
        // TODO: Report error anyhow
        return;
    }
    QString host = account->param("host");
    QString strPort = account->param("port");
    QString password = account->param("stored_password");

    if (host != QString()) {
        d->client->setServer(host.toStdString());
        if (strPort != QString()) {
            bool ok;
            int port = strPort.toInt(&ok);
            if (!ok || port <= 0 || port >= 65536) {
                port = DEFAULT_PORT;
            }
            d->client->setPort(port);
        }
    }

    d->client->setPassword(password.toStdString());
    d->client->setPresence(presence);
    d->sessionThread->start();
}

void Kajim::XMPP::Connection::logout()
{
    d->client->disconnect();
}

void Kajim::XMPP::Connection::sendMessage(const QString & peerJid, const QString & body, const QString & subject)
{
    qDebug() << "Send message to jid:" << peerJid;
    gloox::MessageSession * ms = messageSession(peerJid);
    ms->send(Kajim::XMPP::stdString(body), Kajim::XMPP::stdString(subject));
}




